package com.bright.cwduijie.duijie.service.impl;

import com.bright.cwduijie.common.util.StringUtil;
import com.bright.cwduijie.duijie.converter.VoucherConverter;
import com.bright.cwduijie.duijie.converter.VoucherEntryConverter;
import com.bright.cwduijie.duijie.enums.DataApi;
import com.bright.cwduijie.duijie.enums.OpType;
import com.bright.cwduijie.duijie.enums.SJJHBZ;
import com.bright.cwduijie.duijie.pojo.bo.ApiDataCollection;
import com.bright.cwduijie.duijie.pojo.dto.CheckResultDto;
import com.bright.cwduijie.duijie.pojo.dto.VoucherDto;
import com.bright.cwduijie.duijie.pojo.dto.VoucherEntryDto;
import com.bright.cwduijie.duijie.pojo.po.Voucher;
import com.bright.cwduijie.duijie.pojo.po.VoucherEntry;
import com.bright.cwduijie.duijie.pojo.query.DuijieQuery;
import com.bright.cwduijie.duijie.pojo.vo.VoucherEntryVO;
import com.bright.cwduijie.duijie.pojo.vo.VoucherVO;
import com.bright.cwduijie.duijie.repository.VoucherEntryRepository;
import com.bright.cwduijie.duijie.repository.VoucherRepository;
import com.bright.cwduijie.duijie.service.AbstractMonthlyReportApiService;
import com.bright.cwduijie.duijie.util.ListUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.function.Function;

/**
 * @Author hxj
 * @Date 2024/8/2 13:08
 * @Description 凭证类 月度报表类型
 */

@Component
@RequiredArgsConstructor
@Slf4j
public class ApiVoucherServiceImpl extends AbstractMonthlyReportApiService<VoucherDto, VoucherVO> {

    private final VoucherRepository voucherRepository;
    private final VoucherEntryRepository voucherEntryRepository;
    private final VoucherConverter voucherConverter;
    private final VoucherEntryConverter voucherEntryConverter;

    @Override
    public JpaSpecificationExecutor getJpaSpecificationExecutor() {
        return voucherRepository;
    }

    @Override
    public DataApi getDataApi() {
        return DataApi.VOUCHER;
    }

    @Override
    public Function<VoucherDto, Integer> getIdFunc() {
        return VoucherDto::getId;
    }

//    @Override
    public Function<VoucherDto, String> getDataKeyFunc() {
        return VoucherDto::getDATA_KEY;
    }

    @Override
    public Function<ApiDataCollection, Map<String, List<VoucherDto>>> getDataFunc() {
        return ApiDataCollection::getVoucherMap;
    }

    @Override
    public Function<VoucherDto, VoucherVO> getConverterFunc() {
        return voucherConverter::dtoConvertVO;
    }

    @Override
    public boolean isExistsTYSHXYDMField() {
        return false;
    }

    @Override
    protected void getData(ApiDataCollection apiDataCollection, DuijieQuery duijieQuery) {
        List<String> yearMonths = voucherRepository.getDistinctKJQJByZtDataKeyAndSjjhbz(duijieQuery.getZtDataKey(), Arrays.asList(SJJHBZ.WAITING.getValue(), SJJHBZ.ERROR.getValue()));
        Map<String, List<VoucherDto>> result = new HashMap<>();

        // 20240725 加上判断是否有指定对接年月 若有指定就只返回指定年月的数据 没有就返回全部
        // 比如只指定了2024年 则selectedYearMonth=2024  若指定2024年1月 则=202401
        String selectedYearMonth = getSelectedYearMonth(duijieQuery);

        for (String yearMonth : yearMonths) {
            if (selectedYearMonth == null || StringUtil.startsWith(yearMonth, selectedYearMonth)) {
                // 只推送选定年月的数据
                List<Voucher> vouchers = voucherRepository.getByZTDATAKEYAndKJQJAndOpTypeAndSjjhbz(duijieQuery.getZtDataKey(), yearMonth, OpType.ADD_OR_EDIT.getValue(), Arrays.asList(SJJHBZ.WAITING.getValue(), SJJHBZ.ERROR.getValue()));
                result.put(yearMonth, voucherConverter.poConvertDTO(vouchers));
            }

        }


        apiDataCollection.setVoucherMap(result);

        Map<String, List<VoucherEntryDto>> voucherEntryMap = new HashMap<>();

        for (List<VoucherDto> voucherDtos : result.values()) {
            for (VoucherDto voucher : voucherDtos) {
                List<VoucherEntry> voucherEntries = voucherEntryRepository.getAllByDataKey(voucher.getDATA_KEY());
                List<VoucherEntryDto> voucherEntryDtos = voucherEntryConverter.poConvertDTO(voucherEntries);
                processVoucherEntries(voucherEntryDtos);

                voucherEntryMap.put(voucher.getDATA_KEY(), voucherEntryDtos);
            }
        }

        apiDataCollection.setVoucherEntryMap(voucherEntryMap);
    }

    @Override
    protected void checkDataValid(Map<String, CheckResultDto> checkResultDtoMap, ApiDataCollection apiDataCollection) {
        checkService.checkDataBeforeSend(checkResultDtoMap, apiDataCollection.getVoucherMap(), DataApi.VOUCHER, VoucherDto::getId);
        checkService.checkDataBeforeSend(checkResultDtoMap, apiDataCollection.getVoucherEntryMap(), DataApi.VOUCHER, VoucherEntryDto::getId);
    }

    @Override
    public void sendData(ApiDataCollection apiDataCollection, DuijieQuery duijieQuery, String batchId) throws JsonProcessingException {
        Map<String, List<VoucherDto>> vouchers = apiDataCollection.getVoucherMap();
        Map<String, List<VoucherEntryDto>> voucherEntryMap = apiDataCollection.getVoucherEntryMap();
        if (vouchers.size() == 0) {
            // 没数据的情况
            sendListData(Collections.emptyList(), Collections.emptyList(), batchId, duijieQuery.getAccSet());
        }
        // 按照会计期间进行划分
        for (Map.Entry<String, List<VoucherDto>> entry : vouchers.entrySet()) {
//            String yearMonth = entry.getKey();
            List<VoucherDto> dtos = entry.getValue();

            if (dtos.size() == 0) {
                // 该年月没有数据 不推送
                continue;
            }

            int count = 0;
            while (count < dtos.size()) {
                List<VoucherDto> subList = ListUtil.getSubList(dtos, count, count + 1000);
                // 判断各个会计期间是否需要传递 只传递已经月结的数据
                // 暂时放行 测试用
                // 程哥改逻辑了 改成是这些业务表上传成功了 才去生成月结数据 所以这里不再校验是否月结
//            if (settledYearMonths.contains(yearMonth)) {

                List<VoucherVO> list = new ArrayList<>();
                for (VoucherDto dto : subList) {
                    VoucherVO vo = voucherConverter.dtoConvertVO(dto);
                    list.add(vo);
                    // 封装子表 凭证分录
                    List<VoucherEntryDto> voucherEntryDtos = voucherEntryMap.get(vo.getDATA_KEY());
                    if (voucherEntryDtos == null) {
                        voucherEntryDtos = Collections.emptyList();
                    }
                    List<VoucherEntryVO> voucherEntryVOS = voucherEntryConverter.dtoConvertVO(voucherEntryDtos);
                    vo.setKJPZ_KJKM_LIST(voucherEntryVOS);
                }

                sendListData(list, ListUtil.toSingleList(subList, getIdFunc()), batchId, duijieQuery.getAccSet());

                saveSendDataKeys(subList, getDataKeyFunc());

//            } else {
//                log.debug(dataApi.getDescription() + "该会计期间未月结，不进行对接：" + yearMonth);
//            }

                count += 1000;
            }
        }


    }

//    @Override
    protected List<VoucherDto> getNeedDeleteData(DuijieQuery duijieQuery) {
        List<Voucher> vouchers = voucherRepository.getByZTDATAKEYAndOpTypeAndSJJHBZ(duijieQuery.getZtDataKey(), OpType.DEL.getValue(), SJJHBZ.WAITING.getValue());
        vouchers.addAll(voucherRepository.getByZTDATAKEYAndOpTypeAndSJJHBZ(duijieQuery.getZtDataKey(), OpType.DEL.getValue(), SJJHBZ.ERROR.getValue()));
        return voucherConverter.poConvertDTO(vouchers);
    }

//    @Override
    protected DataApi getDeleteDataApi() {
        return DataApi.DELETE_VOUCHER;
    }

    @Override
    public void sendDeleteData(DuijieQuery duijieQuery, String batchId) throws JsonProcessingException {
        sendNeedDeleteData(batchId, getNeedDeleteData(duijieQuery), getDeleteDataApi(), getDataKeyFunc(), getIdFunc(), duijieQuery.getAccSet());
    }

    private void processVoucherEntries(List<VoucherEntryDto> voucherEntryDtos) {
        // 第三方要求借方或贷方没有数值的 不能传0 应该传null
        for (VoucherEntryDto voucherEntry : voucherEntryDtos) {
            String jf_je = voucherEntry.getJF_JE();
            String df_je = voucherEntry.getDF_JE();
            if (StringUtil.equals(jf_je, "0.00") || StringUtil.equals(jf_je, "0.0") || StringUtil.equals(jf_je, "0")) {
                voucherEntry.setJF_JE("");
            }
            if (StringUtil.equals(df_je, "0.00") || StringUtil.equals(df_je, "0.0") || StringUtil.equals(df_je, "0")) {
                voucherEntry.setDF_JE("");
            }

            // 去空格
            voucherEntry.setKJKM_BM(StringUtil.trim(voucherEntry.getKJKM_BM()));
        }
    }

    @Override
    public String getCheckDuplicateGroupByFields() {
        return "DATA_KEY";
    }
}
